<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>UDP Networking</title>
  </head>
  
  <body>
    <h1>UDP Networking</h1>
    
    <h2>Overview</h2>
    
    <p>Unlike TCP, UDP has no notion of connections. A UDP socket can receive
    datagrams from any server on the network, and send datagrams to any host
    on the network. In addition, datagrams may arrive in any order, never
    arrive at all, or be duplicated in transit.</p>

    <p>Since there are no multiple connections, we only use a single object,
    a protocol, for each UDP socket. We then use the reactor to connect
    this protocol to a UDP transport, using the 
    <code class="API">twisted.internet.interfaces.IReactorUDP</code>
    reactor API.</p>
    
    <h2>DatagramProtocol</h2>

    <p>At the base, the place where you actually implement the protocol
    parsing and handling, is the DatagramProtocol class. This class will
    usually be decended from <code
    class="API">twisted.internet.protocol.DatagramProtocol</code>. Most
    protocol handlers inherit either from this class or from one of its
    convenience children. The DatagramProtocol class receives datagrams, and
    can send them out over the network. Received datagrams include the
    address they were sent from, and when sending datagrams the address to
    send to must be specified.</p>
    
    <p>Here is a simple example:</p>
    <pre class="python">
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class Echo(DatagramProtocol):
    
    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)
        self.transport.write(data, (host, port))

reactor.listenUDP(9999, Echo())
reactor.run()
    </pre>
    
    <p>As you can see, the protocol is registed with the reactor. This means
    it may be persisted if it's added to an application, and thus it has
    <code
    class="API">twisted.internet.protocol.DatagramProtocol.startProtocol</code>
    and <code
    class="API">twisted.internet.protocol.DatagramProtocol.stopProtocol</code>
    methods that will get called when the protocol is connected and
    disconnected from a UDP socket.</p>

    <p>The protocol's <code class="python">transport</code> attribute will
    implement the <code
    class="API">twisted.internet.interfaces.IUDPTransport</code> interface.
    Notice that the <code class="python">host</code> argument should be an
    IP, not a hostname. If you only have the hostname use <code
    class="python">reactor.resolve()</code> to resolve the address (see <code
    class="API">twisted.internet.interfaces.IReactorCore.resolve</code>).</p>


    <h2>Connected UDP</h2>

    <p>A connected UDP socket is slighly different from a standard one - it
    can only send and receive datagrams to/from a single address, but this
    does not in any way imply a connection. Datagrams may still arrive in any
    order, and the port on the other side may have no one listening. The
    benefit of the connected UDP socket is that it it <strong>may</strong>
    provide notification of undelivered packages. This depends on many
    factors, almost all of which are out of the control of the application,
    but it still presents certain benefits which occassionally make it
    useful.</p>

    <p>Unlike a regular UDP protocol, we do not need to specify where to
    send datagrams to, and are not told where they came from since
    they can only come from address the socket is 'connected' to.</p>

    <pre class="python">
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class Helloer(DatagramProtocol):

    def startProtocol(self):
        self.transport.connect("192.168.1.1", 1234)
        print "we can only send to %s now" % str((host, port))
        self.transport.write("hello") # no need for address
        
    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)

    # Possibly invoked if there is no server listening on the
    # address to which we are sending.
    def connectionRefused(self):
        print "No one listening"

# 0 means any port, we don't care in this case
reactor.listenUDP(0, Helloer())
reactor.run()
    </pre>

    <p>Note that <code class="python">connect()</code>, like <code
    class="python">write()</code> will only accept IP addresses, not
    unresolved domain names. To obtain the IP of a domain name use <code
    class="python">reactor.resolve()</code>, e.g.:</p>

  <pre class="python">
from twisted.internet import reactor

def gotIP(ip):
    print "IP of 'example.com' is", ip

reactor.resolve('example.com').addCallback(gotIP)
    </pre>

    <p>Connecting to a new address after a previous connection, or
    making a connected port unconnected are not currently supported,
    but will likely be supported in the future.</p>

    <h2>Multicast UDP</h2>

    <p>A multicast UDP socket can send and receive datagrams from multiple clients.
    The interesting and useful feature of the multicast is that a client can
    contact multiple servers with a single packet, without knowing the specific IP
    of any of the hosts.</p>
    
    <a href="listings/udp/MulticastServer.py"
    class="py-listing">MulticastServer.py</a>

    <p>
    The server protocol is very simple, and closely resembles a normal listenUDP
    implementation.  The main difference is that instead of listenUDP,
    listenMulticast is called with a specified port number.  The server must also
    call joinGroup to specify on which multicast IP address it will service
    requests.  Another item of interest is the contents of the datagram.  Many
    different applications use multicast as a way of device discovery, which leads
    to an abundance of packets flying around.  Checking the payload can ensure
    that we only service requests from our specific clients.
    </p>

    <a href="listings/udp/MulticastClient.py"
    class="py-listing">MulticastServer.py</a>

    <p>
    This is a mirror implementation of a standard UDP client.  The only difference
    is that the destination IP is the multicast address.  This datagram will be
    distributed to every server listening on 224.0.0.1 and port 8005.  Note that
    the client port is specified as 0, as we have no need to keep track of what
    port the client is listening on.
    </p>

<h2>Acknowledgements</h2>

<p>Thank you to all contributors to this document, including:</p>

<ul>
<li>Kyle Robertson, author of the explanation and examples of multicast</li>
</ul>

</body>
</html>
